package com.gs.process.admin.service;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gs.process.admin.utils.ProcessUtil;
import com.gs.process.core.handler.ProcessHandlerService;
import com.gs.process.core.user.ProcessUserService;
import com.gs.process.model.Approval;
import com.gs.process.model.ApprovalDetails;
import com.gs.process.model.ProcessNode;
import com.gs.process.admin.mapper.ApprovalDetailsMapper;
import com.gs.process.model.dto.ApprovalDto;
import com.gs.process.model.dto.Constant;
import com.shallowUniverse.http.HttpApiService;
import com.shallowUniverse.http.pojo.HttpResult;
import com.shallowUniverse.utils.AssertUtil;
import com.shallowUniverse.utils.PrimaryKeyUtil;
import com.shallowUniverse.utils.StreamUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author gs
 * @date create in 2020/12/11 16:34
 */
@Service
public class ApprovalDetailsService extends ServiceImpl<ApprovalDetailsMapper, ApprovalDetails> {

    @Resource
    private ApprovalDetailsMapper approvalDetailsMapper;
    @Resource
    private ApprovalService approvalService;
    @Resource
    private ProcessNodeService processNodeService;
    @Resource
    private ProcessUserService processUserService;
    @Resource
    private HttpApiService httpApiService;

    @Transactional(rollbackFor = Exception.class)
    public boolean save(ApprovalDetails approvalDetails, HttpServletRequest request) {
        //判断是否为空
        if (ObjectUtils.isEmpty(approvalDetails)) {
            return false;
        }
        //设置默认值
        approvalDetails.setCreateDate(DateUtil.now());
        approvalDetails.setUserId(processUserService.getUserId());
        approvalDetails.setSid(PrimaryKeyUtil.generate());
        //查询审批单
        Approval approval = approvalService.findById(approvalDetails.getApprovalId());
        AssertUtil.service().notNull(approval, "找不到对应的审批单");
        //先根据角色和部门查询当前登录用户是否存在审批角色
        List<ProcessNode> nodes = processNodeService.list(
                new QueryWrapper<ProcessNode>().lambda()
                        .eq(ProcessNode::getProcessId, approval.getProcessId())
                        .in(ProcessNode::getRoleId, processUserService.getUserRoles())
                        .and(lambda -> lambda.eq(ProcessNode::getDeptId, processUserService.getUserDept())
                                .or()
                                .isNull(ProcessNode::getDeptId)
                        ).orderByDesc(ProcessNode::getSeq)
        );
        //判断是否有，如果没有证明没权限
        AssertUtil.service().notEmpty(nodes, "权限不足");
        //设置存在于当前审批节点中的节点到审批详情
        approvalDetails.setProcessNodeId(
                nodes.stream()
                        .map(processNode -> processNode.getSid().toString())
                        .filter(approvalDetails.getProcessNodeId()::contains)
                        .collect(Collectors.joining(","))
        );
        //保存审批详情
        int count = approvalDetailsMapper.insert(approvalDetails);
        //封装请求数据
        ApprovalDto approvalDto = new ApprovalDto();
        approvalDto.setApproval(approval);
        approvalDto.setApprovalDetails(approvalDetails);
        //获取请求ip地址
        String ipAddress = getIpAddress(request);
        //判断是通过还是驳回
        if (Constant.AUDIT_REFUSE_SIGN.equals(approvalDetails.getInfo())) {
            //修改单子状态为驳回
            approval.setStatus(Constant.PROCESS_REFUSE_SIGN);
            //调用处理器
            this.postHandle(ipAddress,approvalDto);
        } else {
            //查找下一个节点
            List<ProcessNode> processNodes = processNodeService.listByIds(Arrays.stream(approvalDetails.getProcessNodeId().split(",")).map(Long::parseLong).collect(Collectors.toList()));
            List<ProcessNode> nextNodes = processNodeService.list(
                    new QueryWrapper<ProcessNode>().lambda()
                            .eq(ProcessNode::getProcessId, approval.getProcessId())
                            .eq(ProcessNode::getSeq, processNodes.get(0).getSeq() + 1)
            );
            //拿到当前节点
            ProcessNode currentNode = processNodes.get(0);
            //判断是否存在 或 是否需要提前结束流程
            if (CollectionUtils.isEmpty(nextNodes)
                    || ProcessUtil.validate(approval, currentNode, httpApiService, ipAddress)) {
                //判断是会签还是或签
                if (ObjectUtils.isEmpty(currentNode.getMode()) || Constant.OR.equalsIgnoreCase(currentNode.getMode())
                        || ProcessUtil.allAllowed(processNodeService, approvalDetailsMapper, approval, currentNode)) {
                    //证明已经完成流程
                    approval.setStatus(Constant.PROCESS_ALLOW_SIGN);
                    //重置当前节点为当前顺序所有节点
                    List<ProcessNode> currentNodeList = processNodeService.list(
                            new QueryWrapper<ProcessNode>().lambda()
                                    .eq(ProcessNode::getProcessId, approval.getProcessId())
                                    .eq(ProcessNode::getSeq, currentNode.getSeq())
                    );
                    approval.setCurrent(StreamUtil.join(currentNodeList, ProcessNode::getSid, ","));
                    //调用处理器
                    this.postHandle(ipAddress,approvalDto);
                } else {
                    //移除当前审批过的节点
                    //判断是否是最后一个节点
                    if (!CollectionUtils.isEmpty(nextNodes)/* && !ProcessUtil.validate(approval, currentNode, processNodeService, approvalService)*/) {
                        approval.setCurrent(ProcessUtil.removeNode(approval.getCurrent(), currentNode.getSid()));
                    }
                }
            } else {
                //判断是否可以继续往下走流程
                if (ObjectUtils.isEmpty(currentNode.getMode()) || Constant.OR.equalsIgnoreCase(currentNode.getMode())
                        || ProcessUtil.allAllowed(processNodeService, approvalDetailsMapper, approval, currentNode)) {
                    //继续往下走流程
                    approval.setCurrent(StreamUtil.join(nextNodes, ProcessNode::getSid, ","));
                    //清空委派人
                    approval.setAppoint(null);
                } else {
                    //移除当前审批过的节点
                    approval.setCurrent(ProcessUtil.removeNode(approval.getCurrent(), currentNode.getSid()));
                }
            }
        }
        //更新审批单
        approvalService.updateById(approval);
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean remove(List<Long> ids) {
        //判断是否传了id
        AssertUtil.service().notEmpty(ids, "请传递正确的参数");
        //删除
        approvalDetailsMapper.deleteBatchIds(ids);
        return true;
    }

    private void postHandle(String ipAddress, ApprovalDto approvalDto) {
        try {
            HttpResult httpResult = httpApiService.doPost("http://" + ipAddress + ":9001/handle", null, approvalDto);
            if (httpResult.getCode() == 200) {
                log.debug("处理器调用成功..........");
            }
        } catch (IOException e) {
            e.printStackTrace();
            log.debug("处理器调用失败...............");
        }
    }

    private String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
